[Python] boto3で耐障害性を備えたAssume Roleの方法を考える
こんにちは。サービス開発室の武田です。
ここ2日間くらいずっとSTSのことを考えています。これが恋でしょうか?
先日のSTSの障害を受けて、ベストプラクティスについてやリージョナルエンドポイントのことなど考え直す機会が増えています。
システムがある程度の規模以上になると、AWSアカウントを分けるというのはよくあるパターンのひとつです。その際に、分割先のアカウントのリソースへアクセスするために一時クレデンシャルを使用(スイッチロール/AssumeRole)するのは頻出パターンですね。
さて一時クレデンシャルの払い出しにはSTSを利用するわけですが、その際のコーディングパターンについて考え直す機会となりました。それはSTSの障害に対して冗長性を持たせたコードにするにはどうしたらいいかということです。コードの前に要件をまとめます。
- エンドポイントはリージョナルエンドポイントを使用するのがベストプラクティス
- 地理的に近いエンドポイントを使用するのがよい
- 普段使いのエンドポイントが倒れても別のエンドポイントを使用するフォールバックのしくみが欲しい
- STSのリージョナルエンドポイントは、バージニア北部を除き有効/無効が切り替えられる
- 使用可能なSTSリージョナルエンドポイントは スイッチ先のアカウントに依存 する
特定の少数のアカウントにスイッチするのであれば東京リージョン決めうちなどでも問題ありませんが、そうでない場合、東京リージョンを無効にされたらスイッチできません。そのため障害がなかったとしても、フォールバック先としてバージニア北部は必須と考えます。
バージニア北部のリージョナルエンドポイントがダメだった場合、グローバルエンドポイントも試行すべきでしょうか?これは考えてみたのですがよくわかりませんでした。バージニア北部で障害があった場合はどちらも接続できなそうに思えます。ここら辺の情報がありましたら教えてください。
システムが稼働するリージョンを東京と仮定した場合、東京→大阪→バージニア北部の順に試行するといい感じでしょう。先ほど挙げた5つの要件を満たせそうです。
コードは次のようなものになりました。STSのリージョナルエンドポイントを指定する場合はregion_name
とendpoint_url
を指定します[1]。
import logging
import boto3
STS_REGIONS = ["ap-northeast-1", "ap-northeast-3", "us-east-1"]
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def handler(event, context):
for region in STS_REGIONS:
try:
sts = boto3.client("sts", region_name=region, endpoint_url=f"https://sts.{region}.amazonaws.com")
res = sts.assume_role(RoleArn="arn:aws:iam::123456789012:role/test-role", RoleSessionName="test")
logger.info(f"assume_role success: {region}")
break
except Exception as e:
logger.warning(e)
# STS_REGIONS全て失敗したら諦める
if region == STS_REGIONS[-1]:
raise e
print(res)
動作確認として東京リージョンのSTSを無効化して動かしてみました。ログは次のように出力されました。
[WARNING] 2024-08-31T09:00:00.000Z de47c266-1f49-4f14-956a-35ef866cd793 An error occurred (RegionDisabledException) when calling the AssumeRole operation: STS is not activated in this region for account:123456789012. Your account administrator can activate STS in this region using the IAM Console.
[INFO] 2024-08-31T09:00:00.000Z de47c266-1f49-4f14-956a-35ef866cd793 assume_role success: ap-northeast-3
{'Credentials': {'AccessKeyId': '...', ...}}
東京はRegionDisabledException
のエラーで失敗していますが、次の大阪で成功しています。無事に一時クレデンシャルが取得できていますね。
まとめ
STSで障害が起きても復旧するまで待つことができるスクリプトであればここまでは必要ない可能性はあります。その場合は単にリージョナルエンドポイントを使用するようにするだけでもいいでしょう。一方である程度の規模で動いているシステムであればこういったしくみを導入して耐障害性を高めるのがよいでしょう。
この方法がベストかどうかはまだ検証が足りていませんが、ひとまず運用保守しているシステムでは導入して様子を見てみるつもりです。
参考URL
- https://dev.classmethod.jp/articles/why-aws-sts-regional-endpoints-are-recommended/
- https://dev.classmethod.jp/articles/aws-sts-using-reginal-endpoint-envvar-boto3/
以前はどちらも指定しないとエラーになったのですが、先ほど試した限りはendpoint_urlを指定しなくても正常動作しました。 ↩︎